﻿using System;
using System.Data;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace NSDecisionTree.Graphic
{
    class DrawTree
    {
        DTree.Tree decisionTree;
        Graph graph;
        Bitmap bmpTree;
        List<string> allLeafValues;
        List<Color> leafColor;
        const int boxWidth = 140;
        const int boxHeight = 50;
        const int edgeHeight = 50;

        public Bitmap BmpTree
        {
            get { return bmpTree; }
        }

        public DrawTree(DataTable decisionTable) : this(decisionTable, String.Empty)
        {
        }

        public DrawTree(DataTable decisionTable, String RootElement)
        {
            decisionTree = new DTree.Tree();
            if (String.IsNullOrEmpty(RootElement))
                decisionTree.CreateDecisionTree(decisionTable);
            else
                decisionTree.CreateDecisionTree(decisionTable, RootElement);

            graph = new Graph();
            graph.CreateGraph(decisionTree);
            bmpTree = null;
            fillColor();
            allLeafValues = graph.RootNode.getAllLeafValues();
            DrawGraphic();
        }

        private void fillColor()
        {
            leafColor = new List<Color>();
            leafColor.Add(Color.Green);
            leafColor.Add(Color.Yellow);
            leafColor.Add(Color.Red);
            leafColor.Add(Color.Blue);
            leafColor.Add(Color.Orange);
            leafColor.Add(Color.Gold);
            leafColor.Add(Color.Navy);
            leafColor.Add(Color.Olive);
            leafColor.Add(Color.SeaGreen);
        }

        private void DrawGraphic()
        {
            int highestNodeCount = 0;
            int levelToDraw = graph.LevelItemsCount.Count;

            foreach (int i in graph.LevelItemsCount)
            {
                if (i > highestNodeCount)
                {
                    highestNodeCount = i;
                }
            }

            int width = (highestNodeCount * boxWidth) + ( (highestNodeCount + 1) * 20);
            int height = (levelToDraw * boxHeight) + ((levelToDraw - 1) * edgeHeight) + 10;

            Bitmap bitmap = new Bitmap(width, height);
            
            using (System.Drawing.Graphics g = Graphics.FromImage(bitmap)) 
            {
                for (int i = 0; i < levelToDraw; i++)
                {
                    int currentItems = graph.LevelItemsCount[i];
                    int spaceLeft = (width - (currentItems * boxWidth)) / (currentItems + 1);
                    int edgesDrawnInThisIteration = 0;

                    for (int j = 0; j < currentItems; j++ )
                    {
                        int x = spaceLeft * (j + 1) + ( (j ) * boxWidth);
                        int y = (i * (boxHeight + edgeHeight)) + 5;
                        
                        // rectangle 
                        // TODO: hier leere Nodes nicht ausgeben
                        Rectangle rect = new Rectangle(x, y, boxWidth, boxHeight);
                        graph.RootNode.SetXYPos(i, j, x, y);

                        bool leaf = graph.RootNode.IsLeaf(i, j);
                        bool emptyNode = false;

                        if (leaf)
                        {
                            string tempText = graph.RootNode.GetStringItem(i, j);
                            if (tempText == String.Empty)
                                emptyNode = true;

                            if (!emptyNode || Tools.Tools.OPTION_SHOW_ALL)
                            {
                                int index = allLeafValues.IndexOf(graph.RootNode.GetStringItem(i, j));
                                if (index <= leafColor.Count - 1)
                                    g.FillRectangle(new SolidBrush(leafColor[index]), rect);
                                else
                                    g.FillRectangle(new SolidBrush(leafColor[leafColor.Count - 1]), rect);
                            }
                        }
                        else
                            g.DrawRectangle(new Pen(Color.Black), rect);

                        // text
                        if (!emptyNode)
                        {
                            string text = graph.RootNode.GetStringItem(i, j);
                            string text2 = graph.RootNode.GetAdditionalInfo(i, j);
                            FontStyle fs = FontStyle.Regular;
                            if (leaf)
                                fs = FontStyle.Bold;

                            Font f = new Font(new FontFamily("Verdana"), 12f, fs);
                            Font f2 = new Font(new FontFamily("Verdana"), 9f, fs);
                            g.DrawString(text, f, new SolidBrush(Color.Black), x + 5, y + (int)(boxHeight / 6));
                            g.DrawString(text2, f2, new SolidBrush(Color.Black), x + 5, y + (int)(boxHeight * 2 / 4));

                            // hier Edges
                            if (i != levelToDraw - 1)
                            {
                                int itemsInNextLevelAll = graph.LevelItemsCount[i + 1];
                                int itemsInNextLevel = graph.RootNode.getChildrenCount(i, j);

                                int startPointX = x + (int)(boxWidth / 2);
                                int startPointY = y + (int)(boxHeight);
                                int spaceLeftNextLevel = (width - (itemsInNextLevelAll * boxWidth)) / (itemsInNextLevelAll + 1);

                                for (int k = 0; k < itemsInNextLevel; k++)
                                {
                                    string leafText = graph.RootNode.GetStringItem(i + 1, k + edgesDrawnInThisIteration);

                                    if (leafText != String.Empty || Tools.Tools.OPTION_SHOW_ALL)
                                    {
                                        //TODO: hier muss noch Text rein
                                        string textEdge = graph.RootNode.getEdgeText(i + 1, k + edgesDrawnInThisIteration);
                                        // int endpointX = spaceLeftNextLevel * (k + edgesDrawnInThisIteration + 1) + ((k + edgesDrawnInThisIteration) * boxWidth) + edgeHeight;
                                        int endpointX = spaceLeftNextLevel * (k + edgesDrawnInThisIteration + 1) + ((k + edgesDrawnInThisIteration) * boxWidth) + (int)(boxWidth / 2);
                                        // int endpointY = startPointY + (int)(boxWidth / 2);
                                        int endpointY = startPointY + edgeHeight;

                                        int stringX = endpointX - (int)(boxWidth / 4);
                                        int stringY = endpointY - 30;

                                        g.DrawString(textEdge, new Font(new FontFamily("Arial"), 10f), new SolidBrush(Color.Black), stringX, stringY);
                                        g.DrawLine(new Pen(Color.Black), startPointX, startPointY, endpointX, endpointY);
                                    }
                                }
                                edgesDrawnInThisIteration += itemsInNextLevel;
                            }
                        }
                    }
                }
            }
            bmpTree = bitmap;
            //TODO: hier Graphic Drawen
        }

        public Node getNodes(int x, int y, float multiplier)
        {
            return graph.RootNode.getNodeInRange(x, y, boxWidth, boxHeight, multiplier);
        }
    }
}
